/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.metadata.rtcustomization.servermanager.dac;

import com.inspur.edp.metadata.rtcustomization.api.entity.GspMdCustomContent;
import com.inspur.edp.metadata.rtcustomization.api.entity.GspMdCustomContentData;
import com.inspur.edp.metadata.rtcustomization.api.exception.ErrorCodes;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmMetadataException;
import com.inspur.edp.metadata.rtcustomization.common.PredicateUtils;
import com.inspur.edp.metadata.rtcustomization.servermanager.utils.MetadataStorageUtils;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import lombok.var;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

public class GeneratedRepo {
	private CustomizationDataProducer cdp;
	public GeneratedRepo(CustomizationDataProducer cdp) {
		this.cdp = cdp;
	}

	public GspMdCustomContent getGeneratedMetadataById(String id) {
		if (StringUtils.isEmpty(id)) {
			return null;
		}
		CustomizationMetadataRepository customizationMetadataRepository = SpringBeanUtils.getBean(CustomizationMetadataRepository.class);
		GspMdCustomContent gspMdCustomContent = customizationMetadataRepository.findById(id).orElse(null);
		if (gspMdCustomContent == null) {
			return null;
		}
		// 如果是文件化，并且上下文中有租户信息，则要进行租户越权校验
		if (MetadataStorageUtils.isUsingSecondDatasource() && CAFContext.current.getTenantId() != -1) {
			// 如果元数据的tenantId不为null，并且tenantId和上下文中的不一样，则不可以获取
			if (gspMdCustomContent.getTenantId() != null && gspMdCustomContent.getTenantId() != CAFContext.current.getTenantId()) {
				throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0023, gspMdCustomContent.getName());
			}
		}
		return gspMdCustomContent;
	}

	public List<GspMdCustomContent> getGeneratedList() {
		CustomizationMetadataRepository customizationMetadataRepository = SpringBeanUtils.getBean(CustomizationMetadataRepository.class);
		// 如果是文件化，并且上下文中有租户信息，过滤掉其他租户的元数据
		if (MetadataStorageUtils.isUsingSecondDatasource() && CAFContext.current.getTenantId() != -1) {
            return customizationMetadataRepository.findAllGspMdCustomContentsByTenantId(CAFContext.current.getTenantId());
		}
		// 非文件化，或者上下文中没有租户信息（没有租户信息，说明没有用户登录，获取的元数据和租户无关），即CAFContext.current.getTenantId() == -1，返回所有元数据
        return customizationMetadataRepository.findAllGspMdCustomContents();
	}

	/**
	 * 根据条件获取生成的元数据列表
	 * 分页查询，用在设计时元数据选择器。文件化多租户下用不到，暂不修改。
	 *
	 * @param keyword
	 * @param metadataTypes
	 * @param beginNum
	 * @param size
	 * @return
	 */
	public List<GspMdCustomContent> getGeneratedListByCondition(String keyword, String bizobjectID, List<String> metadataTypes, int beginNum, int size) {
		EntityManager entityManager = cdp.getEm();
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<GspMdCustomContent> query = cb.createQuery(GspMdCustomContent.class);
		Root<GspMdCustomContent> root = query.from(GspMdCustomContent.class);
		// 实际查询字段
		query.multiselect(root.get("id"), root.get("code"), root.get("name"), root.get("type"), root.get("bizObjId"), root.get("isExtend"), root.get("nameSpace"));
		Predicate finalPredicate = PredicateUtils.buildMdQueryPredicate(keyword, bizobjectID, metadataTypes, null,cb, root,GspMdCustomContent.class);
		query.where(finalPredicate);

		// 执行查询，获取总记录数
		List<GspMdCustomContent> resultList = entityManager.createQuery(query).setFirstResult(beginNum).setMaxResults(size).getResultList();
		return resultList;
	}

	/**
	 * 根据条件获取生成的元数据的数量
	 * 分页查询，用在设计时元数据选择器。文件化多租户下用不到，暂不修改。
	 *
	 * @param keyword
	 * @param metadataTypes
	 * @return
	 */
	public long getGeneratedListCountByCondition(String keyword, String bizobjectID, List<String> metadataTypes) {
		EntityManager entityManager = cdp.getEm();
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Long> query = cb.createQuery(Long.class);
		Root<GspMdCustomContent> root = query.from(GspMdCustomContent.class);
		// 实际查询字段
		query.select(cb.count(root));
		Predicate finalPredicate = PredicateUtils.buildMdQueryPredicate(keyword, bizobjectID, metadataTypes, null, cb, root,GspMdCustomContent.class);
		query.where(finalPredicate);

		// 执行查询，获取总记录数
		Long count = entityManager.createQuery(query).getSingleResult();
		return count;
	}

	/**
	 * 根据元数据id获取元数据列表
	 * 方法不合理，一个元数据id只能获取到一个元数据，未使用，废弃
	 * @param id 元数据id
	 * @return 元数据列表
	 */
	@Deprecated
	public List<GspMdCustomContent> getGeneratedListById(String id) {
		CustomizationMetadataRepository customizationMetadataRepository = SpringBeanUtils.getBean(CustomizationMetadataRepository.class);
		List<GspMdCustomContentData> gspMdCustomContentDataList = customizationMetadataRepository.findAllGspMdCustomContents(id);
		return getMetadataFromDatabase(gspMdCustomContentDataList);
	}

	/**
	 * 转元数据实体
	 * 无用，废弃
	 */
	@Deprecated
	private List<GspMdCustomContent> getMetadataFromDatabase(List<GspMdCustomContentData> gspMdCustomContentDataList) {
		List<GspMdCustomContent> metadataList = new ArrayList<>();
		if(CollectionUtils.isEmpty(gspMdCustomContentDataList)){
			return metadataList;
		}
		for (GspMdCustomContentData gspMdCustomContentData : gspMdCustomContentDataList) {
			var metadata = new GspMdCustomContent();
			BeanUtils.copyProperties(gspMdCustomContentData,metadata);
			metadataList.add(metadata);
		}
		return metadataList;
	}

	/**
	 * 查询所有元数据的最后修改时间
	 * 用于启动后事件清除元数据缓存，后面会去掉。不影响文件化多租户，不修改。
	 *
	 * @return 元数据最后修改时间列表
	 */
	public List<GspMdCustomContent> findAllLastChangedOn() {
		CustomizationMetadataRepository customizationMetadataRepository = SpringBeanUtils.getBean(CustomizationMetadataRepository.class);
		return customizationMetadataRepository.findAllLastChangedOn();
	}

	/**
	 * 更新所有最后修改时间为Null的元数据的最后修改时间
	 * 用于检查元数据最后修改时间的的程序集，后面已无用。不影响文件化多租户，不修改。
	 */
	public void updateLastChangedOnWhereIsNull() {
		CustomizationMetadataRepository customizationMetadataRepository = SpringBeanUtils.getBean(CustomizationMetadataRepository.class);
		customizationMetadataRepository.updateLastChangedOnWhereIsNull(LocalDateTime.now());
	}
}
